package web

import (
	"fmt"
	"gitee.com/flycash/xiaohongshu-demo/internal/domain"
	"gitee.com/flycash/xiaohongshu-demo/internal/service"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"strconv"
)

type ArticleController struct {
	service service.ArticleService
}

func NewArticleController(service service.ArticleService) *ArticleController {
	return &ArticleController{service: service}
}

func (a *ArticleController) RegisterRoutes(server *gin.Engine) {
	// 帖子组
	article := server.Group("/article")
	article.Any("/read/:id", a.GetByID)
	article.GET("/new", func(context *gin.Context) {
		context.HTML(http.StatusOK, "write_article.gohtml", nil)
	})
	article.POST("/new", a.Save)
	article.POST("/publish", a.Publish)

	article.Any("/new/success", func(context *gin.Context) {
		context.String(http.StatusOK, "保存成功")
	})

	article.Any("/new/failed", func(context *gin.Context) {
		context.String(http.StatusOK, "保存失败")
	})
}

func (a *ArticleController) GetByID(ctx *gin.Context) {
	idStr := ctx.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		// 随便给一个错误码
		ctx.JSON(http.StatusBadRequest, Resp{Code: 1, Msg: "ID 错误"})
		return
	}
	art, err := a.service.Get(ctx.Request.Context(), id)
	if err != nil {
		// 如果代码严谨的话，这边要区别是真的没有数据，还是服务器出现了异常
		ctx.JSON(http.StatusInternalServerError, Resp{Code: 2, Msg: "找不到对应的帖子"})
		return
	}
	var vo ArticleVO
	vo.init(art)
	ctx.JSON(http.StatusOK, Resp{Data: vo})
}

func (a *ArticleController) Publish(ctx *gin.Context) {
	var vo ArticleVO
	if err := ctx.Bind(&vo); err != nil {
		// 出现 error 的情况下，实际上前端已经返回了
		return
	}
	// 缺乏登录部分，所以直接写死
	var authorID uint64 = 123
	art, err := a.service.Publish(ctx.Request.Context(), domain.Article{
		Title:   vo.Title,
		Content: vo.Content,
		Author: domain.Author{
			ID: authorID,
		},
	})
	if err != nil {
		ctx.String(http.StatusInternalServerError, "系统异常，请重试")
		return
	}
	ctx.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("/article/read/%d", art.ID))
}

func (a *ArticleController) Save(ctx *gin.Context) {
	var vo ArticleVO
	if err := ctx.Bind(&vo); err != nil {
		// 出现 error 的情况下，实际上前端已经返回了
		return
	}
	// 缺乏登录部分，所以直接写死
	var authorID uint64 = 123
	_, err := a.service.Save(ctx.Request.Context(), domain.Article{
		Title:   vo.Title,
		Content: vo.Content,
		Author: domain.Author{
			ID: authorID,
		},
	})
	if err != nil {
		// 这边不能把 error 写回去
		// 暂时我直接输出到控制台
		log.Println(err)
		ctx.String(http.StatusInternalServerError, "系统异常，请重试")
		return
	}
	ctx.Redirect(http.StatusTemporaryRedirect, "/article/new/success")
}

type ArticleVO struct {
	ID      uint64 `form:"id"`
	Title   string `form:"title" binding:"required"`
	Content string `form:"content" binding:"required"`
	// 一般来说，考虑到各种 APP 发版本不容易，
	// 所以数字、货币、日期、国际化之类的都是后端做的
	// 前端就是无脑展示
	Ctime string
	Utime string
}

type Resp struct {
	// 业务错误码。不为 0 则是表示出错了
	Code int
	Msg  string
	Data any
}

func (a *ArticleVO) init(art domain.Article) {
	a.ID = art.ID
	a.Utime = art.Utime.String()
	a.Ctime = art.Ctime.String()
	a.Content = art.Content
	a.Title = art.Title
}
